package top.haijunit.work.core.redis;

import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;

import java.time.Duration;
import java.util.concurrent.CompletableFuture;
import java.util.function.LongUnaryOperator;

/**
 * 基于RAtomicLong原理及封装的工具类
 * <p/>
 * RAtomicLong是Redisson 提供的一个分布式原子长整型类。
 * 它模仿了 Java的java.util.concurrent.atomic.AtomicLong类的行为，但是专为分布式环境设计。
 * RAtomicLong 使用 Redis 作为后端来保证操作的原子性和一致性。
 *
 * @author zhanghaijun
 * @since 2024-08-01
 */
@Slf4j
public class RedissonAtomicWrapper {

    private final RAtomicLong atomicLong;

    public RedissonAtomicWrapper(RedissonClient redisson, String name) {
        this.atomicLong = redisson.getAtomicLong(name);
    }

    /**
     * 原子性地增加值，并在操作后执行回调
     */
    public long incrementAndGet(LongUnaryOperator afterIncrement) {
        long result = atomicLong.incrementAndGet();
        return afterIncrement.applyAsLong(result);
    }

    /**
     * 异步版本的 incrementAndGet
     */
    public CompletableFuture<Long> incrementAndGetAsync() {
        return atomicLong.incrementAndGetAsync().toCompletableFuture();
    }

    /**
     * 原子性地减少值，并在操作后执行回调
     */
    public long decrementAndGet(LongUnaryOperator afterDecrement) {
        long result = atomicLong.decrementAndGet();
        return afterDecrement.applyAsLong(result);
    }

    /**
     * 获取当前值
     */
    public long get() {
        return atomicLong.get();
    }

    /**
     * 设置当前值
     */
    public void set(long newValue) {
        atomicLong.set(newValue);
    }

    /**
     * 如果当前值等于预期值，则以原子方式将该值设置为给定的更新值
     */
    public boolean compareAndSet(long expect, long update) {
        return atomicLong.compareAndSet(expect, update);
    }

    /**
     * 获取并增加，带过期时间
     */
    public long getAndAdd(long delta, long ttl) {
        long result = atomicLong.getAndAdd(delta);
        atomicLong.expire(Duration.ofMillis(ttl));
        return result;
    }

    /**
     * 分布式序列生成器，每次调用返回唯一序列号
     */
    public long nextSequence() {
        return atomicLong.incrementAndGet();
    }

    /**
     * 设置值并指定过期时间
     */
    public void setAndExpire(long newValue, long ttl) {
        atomicLong.set(newValue);
        atomicLong.expire(Duration.ofMillis(ttl));
    }

    /**
     * 带有过期时间的原子性增加
     */
    public long incrementAndGetWithTTL(long ttl) {
        long result = atomicLong.incrementAndGet();
        atomicLong.expire(Duration.ofMillis(ttl));
        return result;
    }

    /**
     * 带有过期时间的原子性减少
     */
    public long decrementAndGetWithTTL(long ttl) {
        long result = atomicLong.decrementAndGet();
        atomicLong.expire(Duration.ofMillis(ttl));
        return result;
    }

    /**
     * 删除这个原子长整型
     */
    public void delete() {
        atomicLong.delete();
    }
}
